package Obsluga;



import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.Set;

import javax.print.attribute.standard.MediaSize.JIS;

import javassist.compiler.ast.NewExpr;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import POJO.HistoriaKonta;
import POJO.HistoriaKredyt;
import POJO.Konto;
import POJO.Kredyt;
import POJO.Lokata;
import POJO.Osoba;
import POJO.Pracownik;

/**
 * Klasa działanie odpowiada za całą obsługę bazy danych. Za jej pośrednictwem mozna operowac na informacjach znajdujących sie w bazie.
 * 
 *
 */
public class Dzialanie {

    private final static Logger logger = LoggerFactory.getLogger(Dzialanie.class);
	public static void main(String []args){
		logger.info("Start");
		HibernateUtil.getSessionFactory();
		//usunKonto("6758222","l");
	dodajKlienta(342, "asd", "imie", "nazwisko", new Date(), "ulica", "kodPocztowy", "miejscowosc");
		//dodajKredyt(34242, "888", 5000, 5, 6, 666);
		//dodajKonto(34242, "0100", 5000);
	//spłata("888", new Date()); //poprawic bo daje max dla calosci a nie dla danego rachunku
		//ostatnieLogowanie(34242, new Date(), "kl");
		//usunKlienta(34242);
		//usunKredyt("999");
		//przelewPrzychodzacy("0100", "wplata na konto", 555, 4450, new Date(), "wyplata");
		//dodajLokate(34242, "55543", 567, 5, 5);
		//usunKonto("0100");
		//usunKlienta(34242);
		logger.info("Stop");
		
	}
	
	/**
	 * Metoda zwraca nam obiekt typu osoba wraz ze wszystkimi jego powiazaniami
	 * @param id identyfikator osoby którą chcemy wczytać
	 * @return Obiekt typu Osoba
	 */

	public static Osoba wczytajOsobe(long id){		
		Osoba o = new Osoba();
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		try {
			tx = session.beginTransaction();
			o = (Osoba) session.load(Osoba.class,(long)id, LockMode.UPGRADE);
			tx.commit();
			session.close();
			return o;
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
				}
		}
		return o;		
	}
	/**
	 * Metoda wczytujaca konto bankowe
	 * @param numer numer konta bankowego które nas intersuje
	 * @return Obiekt typu Konto
	 */
	public static Konto wczytajKonto(String numer){		
		Konto k = new Konto();
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		try {
			tx = session.beginTransaction();
			k = (Konto)session.load(Konto.class,numer,LockMode.READ);
			tx.commit();
			session.close();
			return k;
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
			}
		}
		return k;		
	}
	
	/**
	 * 
	 * @param id
	 * @param haslo
	 * @param imie
	 * @param nazwisko
	 * @param dataUr
	 * @param ulica
	 * @param kodPocztowy
	 * @param miejscowosc
	 */
	public static void dodajKlienta(long id,String haslo,String imie,String nazwisko,
			Date dataUr,String ulica,String kodPocztowy,String miejscowosc)
	{
		
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		Osoba  klient = new Osoba(id, haslo, imie, nazwisko, dataUr, ulica, kodPocztowy, miejscowosc);
		
		try {
			tx = session.beginTransaction();
			session.save(klient);
			tx.commit();
			session.close();
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
			}
		}
	}
	
	
	
	public static void dodajKonto(long idKlienta,String nrRachunku,double stanKonta )
	{
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();

		try {
			tx = session.beginTransaction();
			
			Osoba osoba = (Osoba)session.load(Osoba.class,(long)idKlienta, LockMode.UPGRADE);
			Konto konto = new Konto(nrRachunku, stanKonta,osoba);
			osoba.setPojedynczyRachunek(konto,"k");

			session.save(konto);
			session.save(osoba);
				
			tx.commit();
			session.close();
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
					//logger.debug("Error rolling back transaction");
				}
				throw e;
			}
		}
		
		
	}
	
	public static void dodajLokate(long idKlienta,String nrRachunku,double kwotaWplacona,int iloscMieciecy,double oprocentowanie)
	{
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();

		try {
			tx = session.beginTransaction();
			
			Osoba osoba = (Osoba)session.load(Osoba.class,(long)idKlienta, LockMode.UPGRADE);
			Lokata lokata = new Lokata(nrRachunku,kwotaWplacona,iloscMieciecy,oprocentowanie,osoba);
			osoba.setPojedynczyRachunek(lokata,"l");

			session.save(lokata);
			session.save(osoba);
				
			
			tx.commit();
			session.close();
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
			}
		}
	
	}
	
	public static void dodajKredyt(long idKlienta,String nrRachunku ,double wysokoscKredytu,int iloscMies, double oprocen,
			double wysRaty)
	{
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();

		try {
			tx = session.beginTransaction();
			
			Osoba osoba = (Osoba)session.load(Osoba.class,(long)idKlienta, LockMode.UPGRADE);
			Kredyt kredyt = new Kredyt(nrRachunku,wysokoscKredytu,iloscMies,oprocen,wysRaty,osoba);
			osoba.setPojedynczyRachunek(kredyt,"kr");

			session.save(kredyt);
			session.save(osoba);

			tx.commit();
			session.close();
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
			}
		}
	}
	
	
	public static Boolean czyKontoIstnieje(String nrRachunku)
	{	
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		List <Konto> konto = null;
		try {
			tx = session.beginTransaction();			
			Criteria criteria = session.createCriteria(Konto.class)
		    	.add(Restrictions.eq("nrRachunku", nrRachunku));
			konto = criteria.list();
			
			tx.commit();
			session.close();

		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
				}
		}
		if(konto.size()==1){
			return true;}
		else {return false;}
		
	}
	
	public static Boolean czyLokataIstnieje(String nrRachunku)
	{	
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		List <Lokata> konto = null;
		try {
			tx = session.beginTransaction();			
			Criteria criteria = session.createCriteria(Lokata.class)
		    	.add(Restrictions.eq("nrRachunku", nrRachunku));
			konto = criteria.list();
			
			tx.commit();
			session.close();

		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
				}
		}
		if(konto.size()==1){
			return true;}
		else {return false;}
		
	}
	
	public static Boolean czyKredytIstnieje(String nrRachunku)
	{	
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		List <Kredyt> konto = null;
		try {
			tx = session.beginTransaction();			
			Criteria criteria = session.createCriteria(Kredyt.class)
		    	.add(Restrictions.eq("nrRachunku", nrRachunku));
			konto = criteria.list();
			
			tx.commit();
			session.close();

		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
				}
		}
		if(konto.size()==1){
			return true;}
		else {return false;}
		
	}
	
	public static Boolean czyIdDostepne(long idOsoby)
	{
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		List <Osoba> os = null;
		try {
			tx = session.beginTransaction();			
			Criteria criteria = session.createCriteria(Osoba.class)
		    	.add(Restrictions.eq("identyfikator", idOsoby));
			os = criteria.list();
			
			tx.commit();
			session.close();

		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
				}
		}
		if(os.size()==1){
			return false;}
		else {return true;}
		
	}
	
	public static String zwrocHaslo(long identyfikator){
		
		return wczytajOsobe(identyfikator).getHaslo();
		
	}
	
	public static void zmienAdres(long idKlienta,String ulica,String kodPocztowy, String miejscowosc )
	{
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();

		try {
			tx = session.beginTransaction();			
			Osoba osoba = (Osoba)session.load(Osoba.class,(long)idKlienta, LockMode.UPGRADE);
			
			osoba.setKodPocztowy(kodPocztowy);
			osoba.setUl(ulica);
			osoba.setMiejscowosc(miejscowosc);

			session.save(osoba);				
			session.flush();
			tx.commit();
			session.close();
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
			}
		}
		
		
	}
	
	/**
	 * 
	 * @param id numer pracownika powinniśmy przyjąć że numery pracowników są od 1 do 1000 
	 * @param haslo
	 * @param imie
	 * @param nazwisko
	 * @param dataUr
	 * @param ulica
	 * @param kodPocztowy
	 * @param miejscowosc
	 * @param stanowsiko Administrator / bankier
	 */
	public static void dodajPracownika(long id,String haslo,String imie,String nazwisko,
			Date dataUr,String ulica,String kodPocztowy,String miejscowosc,String stanowsiko)
	{
		
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		Pracownik  pracownik = new Pracownik(id, haslo, imie, nazwisko, dataUr, ulica, kodPocztowy, miejscowosc,stanowsiko);
		
		try {
			tx = session.beginTransaction();
			session.save(pracownik);
			tx.commit();
			session.close();
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
			}
		}
	}
	
	
	public static void zmienHaslo(long idOsoby,String noweHaslo)
	{
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();

		try {
			tx = session.beginTransaction();			
			Osoba osoba = (Osoba)session.load(Osoba.class,(long)idOsoby, LockMode.UPGRADE);
			
			osoba.setHaslo(noweHaslo);

			session.save(osoba);				
			session.flush();
			tx.commit();
			session.close();
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
			}
		}
		
		
	}
	
	/**
	 * Metoda dokonuje wyplaty z naszego konta na inne konto albo wyplate w oddziale banku do naszej kieszeni
	 * W sytuacji wypłata w odzdziale uwzględniamy to wszystko w opisie
	 * @param nrKontaWychodzacego nasze konto dla ktorego jest akcja
	 * @param Opis opisuje jaka to akcja, jakie konto docelowe, a moze wypłata w oddziale (ustandaryzowac)
	 * @param kwotaPrzelewu kwota przelewu 
	 * @param stanKontaPoPrzelewie po wykonaniu operacji jaki jest stan konta naszego
	 * @param data data wykonania operacji
	 * @param rodzajOperacji dostepne opcje wpłata / wypłata
	 */
	public static void przelewWychodzacy(String nrKontaWychodzacego,String opis, double kwotaPrzelewu, 
			double stanKontaPoPrzelewie,Date data,String rodzajOperacji)
	{
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();

		try {
			HistoriaKonta hs = null;
			tx = session.beginTransaction();			
			Konto konto = (Konto)session.load(Konto.class,nrKontaWychodzacego, LockMode.UPGRADE);
			konto.setStanKonta(konto.getStanKonta()-kwotaPrzelewu);
		
				
				 hs = new HistoriaKonta(nrKontaWychodzacego, data, kwotaPrzelewu, stanKontaPoPrzelewie,
						 rodzajOperacji, opis, konto);
			

			
			
			session.save(hs);				
			session.flush();
			tx.commit();
			session.close();
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
			}
		}
		
		
	}
	/**
	 * Metoda pozwala dokonac wpłaty Na konto 
	 * W sytuacji wypłata w odzdziale uwzględniamy to wszystko w opisie
	 * @param nrKontaDocelowego konto na które wpłata ma dojść
	 * @param opis opisuje jaka to akcja, jakie konto docelowe, a moze wypłata w oddziale (ustandaryzowac)
	 * @param kwotaPrzelewu jaka kwota wplynie na konto
	 * @param stanKontaPoPrzelewie stan konta po przelewie
	 * @param data data operacji
	 * @param rodzajOperacji rodzaj operacji dostepne opcje wpłata / wypłata
	 */
	
	
	public static void przelewPrzychodzacy(String nrKontaDocelowego,String opis, double kwotaPrzelewu, 
			double stanKontaPoPrzelewie,Date data,String rodzajOperacji)
	{
		Transaction tx = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();

		try {
			HistoriaKonta hs = null;
			tx = session.beginTransaction();			
			Konto konto = (Konto)session.load(Konto.class,nrKontaDocelowego, LockMode.UPGRADE);
			konto.setStanKonta(konto.getStanKonta()+kwotaPrzelewu);
		
				
				 hs = new HistoriaKonta(nrKontaDocelowego, data, kwotaPrzelewu, stanKontaPoPrzelewie,
						 rodzajOperacji, opis, konto);
			

			
			
			session.save(hs);				
			session.flush();
			tx.commit();
			session.close();
		} catch (RuntimeException e) {
			if (tx != null && tx.isActive()) {
				try {
					tx.rollback();
				} catch (HibernateException e1) {
				//	logger.debug("Error rolling back transaction");
				}
				throw e;
			}
		}
	}
		
		
		/**
		 * Metoda ustawia pole odnosnie ostatnego logowania klienta bądz pracownika
		 * @param identyfikator identyfikator osoby
		 * @param dataLogowania data logowania, którą chcemy ustawić
		 * @param kl_pr parametr dla kogo będziemy ustawiać kl= klient, pr= pracownik
		 */
		public static void ostatnieLogowanie(long identyfikator,Date dataLogowania,String kl_pr)
		{
			Transaction tx = null;
			Session session = HibernateUtil.getSessionFactory().getCurrentSession();

			try {
				HistoriaKonta hs = null;
				tx = session.beginTransaction();
				
				if(kl_pr.equals("kl")){
				Osoba os = (Osoba)session.load(Osoba.class,identyfikator, LockMode.UPGRADE);
				os.setDataOstatniegoLogowania(dataLogowania);
				session.save(os);
				}
				else{
				Pracownik os = (Pracownik)session.load(Pracownik.class,identyfikator, LockMode.UPGRADE);
				os.setDataOstatniegoLogowania(dataLogowania);
				session.save(os);				
				}
				
				

				session.flush();
				tx.commit();
				session.close();
			} catch (RuntimeException e) {
				if (tx != null && tx.isActive()) {
					try {
						tx.rollback();
					} catch (HibernateException e1) {
					//	logger.debug("Error rolling back transaction");
					}
					throw e;
				}
			}

	}
		/**
		 * Metoda do spłaty jednej raty kredytu. Raty numerowane od 1. Automatycznie wyliczane jest, która rata obecnie jest spłacana
		 * @param nrKontaKredytowe
		 * @param dataOperacji
		 */
		
		public static void spłata(String nrKontaKredytowe,Date dataOperacji)
		{
			Transaction tx = null;
			Session session = HibernateUtil.getSessionFactory().getCurrentSession();

			try {
				
				tx = session.beginTransaction();
				
			
				Kredyt kr = (Kredyt)session.load(Kredyt.class,nrKontaKredytowe, LockMode.UPGRADE);
				if (kr.getHistoriaKredyt().isEmpty()){
					HistoriaKredyt hs = new HistoriaKredyt(dataOperacji, 1, kr.getWysokoscRaty(), kr);
					session.save(hs);
				}
				else{
					int i=0;
					//sprawdzamy numer ostatnej splaty aby dokonac inkrementacji
					Set<HistoriaKredyt> his = kr.getHistoriaKredyt();
					for (HistoriaKredyt historiaKredyt : his) {
						if(historiaKredyt.getSplataRatyNr()>i){
							i=historiaKredyt.getSplataRatyNr();
						}
						
					}
					HistoriaKredyt hs = new HistoriaKredyt(dataOperacji, i+1, kr.getWysokoscRaty(), kr);
					
					session.save(hs);
				}
				

				session.flush();
				tx.commit();
				session.close();
			} catch (RuntimeException e) {
				if (tx != null && tx.isActive()) {
					try {
						tx.rollback();
					} catch (HibernateException e1) {
					//	logger.debug("Error rolling back transaction");
					}
					throw e;
				}
			}
	}
		/**
		 * Metoda usówa danego klienta i wszystkie powiązania z nim
		 * @param id
		 */
		public static void usunKlienta(long id)
		{
			Transaction tx = null;
			Session session = HibernateUtil.getSessionFactory().getCurrentSession();

			try {
				
				tx = session.beginTransaction();
				
			
				Osoba os = (Osoba)session.load(Osoba.class,id, LockMode.UPGRADE);
				if(!os.getKonta().isEmpty()){
					Set<Konto> kont = os.getKonta();
					for (Konto konto : kont) {
						usunKonto(konto.getNrRachunku());
					}
				}
				if(!os.getKredyty().isEmpty()){
					Set<Kredyt> kredyt = os.getKredyty();
					for (Konto krr : kredyt) {
						usunKredyt(krr.getNrRachunku());
					}
				}
				if(!os.getLokaty().isEmpty()){
					Set<Lokata> lok = os.getLokaty();
					for (Lokata lokata : lok) {
						usunLokate(lokata.getNrRachunku());
					}
				}
				//session.delete(os);			
				//session.flush();
				pom(id);
				tx.commit();
				session.close();
			} catch (RuntimeException e) {
				if (tx != null && tx.isActive()) {
					try {
						tx.rollback();
					} catch (HibernateException e1) {
					//	logger.debug("Error rolling back transaction");
					}
					throw e;
				}
			}
	}
		
		public static void pom(long id){
			Transaction tx = null;
			Session session = HibernateUtil.getSessionFactory().getCurrentSession();

			try {
				
				tx = session.beginTransaction();
				
			
				Osoba os = (Osoba)session.load(Osoba.class,id, LockMode.UPGRADE);

				session.delete(os);			
				session.flush();
				tx.commit();
				session.close();
			} catch (RuntimeException e) {
				if (tx != null && tx.isActive()) {
					try {
						tx.rollback();
					} catch (HibernateException e1) {
					//	logger.debug("Error rolling back transaction");
					}
					throw e;
				}
			}
			
		}
		/**
		 * Metoda pozwala usunąć wybrany kredyt
		 * @param numerKredytu
		 */
		public static void usunKredyt(String numerKredytu)
		{
			Transaction tx = null;
			Session session = HibernateUtil.getSessionFactory().getCurrentSession();

			try {
				
				tx = session.beginTransaction();
				
				
				Kredyt kr = (Kredyt)session.load(Kredyt.class,numerKredytu, LockMode.UPGRADE);
				if(!kr.getHistoriaKredyt().isEmpty()){
				Set<HistoriaKredyt> historia = kr.getHistoriaKredyt();
				HistoriaKredyt hh= null;
				for (HistoriaKredyt historiaKredyt : historia) {
					hh= historiaKredyt;
					session.delete(hh);
				}}
				
				
				session.delete(kr);			
			
				session.flush();
				tx.commit();
				session.close();
			} catch (RuntimeException e) {
				if (tx != null && tx.isActive()) {
					try {
						tx.rollback();
					} catch (HibernateException e1) {
					//	logger.debug("Error rolling back transaction");
					}
					throw e;
				}
			}
	}
		/**
		 * Metoda usówa konto o podanym numerze
		 * @param numerKonta
		 */
		public static void usunKonto(String numerKonta)
		{
			Transaction tx = null;
			Session session = HibernateUtil.getSessionFactory().getCurrentSession();

			try {
				
				tx = session.beginTransaction();
				
				
				Konto kr = (Konto)session.load(Konto.class,numerKonta, LockMode.UPGRADE);
				if(!kr.getHistoriaKonta().isEmpty()){
				Set<HistoriaKonta> historia = kr.getHistoriaKonta();
				HistoriaKonta hh= null;
				for (HistoriaKonta historiaKonta : historia) {
					hh= historiaKonta;
					session.delete(hh);
				}}
				
				
				session.delete(kr);			
			
				session.flush();
				tx.commit();
				session.close();
			} catch (RuntimeException e) {
				if (tx != null && tx.isActive()) {
					try {
						tx.rollback();
					} catch (HibernateException e1) {
					//	logger.debug("Error rolling back transaction");
					}
					throw e;
				}
			}
	}
		/**
		 * Metoda usówa lokatę o podanym numerze
		 * @param numerLokaty
		 */
	
		public static void usunLokate(String numerLokaty)
		{
			Transaction tx = null;
			Session session = HibernateUtil.getSessionFactory().getCurrentSession();

			try {
				
				tx = session.beginTransaction();
				
				
				Lokata ll = (Lokata)session.load(Lokata.class,numerLokaty, LockMode.UPGRADE);
				session.delete(ll);			
			
				session.flush();
				tx.commit();
				session.close();
			} catch (RuntimeException e) {
				if (tx != null && tx.isActive()) {
					try {
						tx.rollback();
					} catch (HibernateException e1) {
					//	logger.debug("Error rolling back transaction");
					}
					throw e;
				}
			}
	}

	

}
